xtask\tasks\fmt/
house_rules.rs1use crate::Xtask;
5use crate::fs_helpers::git_diffed;
6use crate::fs_helpers::git_ls_files;
7use clap::Parser;
8use std::path::PathBuf;
9
10const PATH_TO_HOUSE_RULES_RS: &str = file!(); mod autogen_comment;
13mod cfg_target_arch;
14mod copyright;
15mod crate_name_nodash;
16mod package_info;
17mod repr_packed;
18mod trailing_newline;
19mod unsafe_code_comment;
20
21#[derive(Parser)]
22#[clap(about = r#"Collection of misc formatting "house rules"
23
24RULES:
25
26 - enforce the presence of the standard Microsoft copyright header
27 - enforce in-repo crate names don't use '-' in their name (use '_' instead)
28 - enforce Cargo.toml files don't include autogenerated "see more keys" comments
29 - enforce Cargo.toml files don't contain author or version fields
30 - enforce files end with a single trailing newline
31 - deny usage of `#[repr(packed)]` (you want `#[repr(C, packed)]`)
32 - justify usage of `cfg(target_arch = ...)` (use `guest_arch` instead!)
33 - justify usage of `expect(unsafe_code)` with an UNSAFETY comment
34 "#)]
35pub struct HouseRules {
36 #[clap(long)]
38 pub fix: bool,
39
40 #[clap(long, conflicts_with = "files")]
42 pub only_diffed: bool,
43
44 pub files: Vec<PathBuf>,
48
49 #[clap(long)]
51 pub skip_copyright: bool,
52
53 #[clap(long)]
55 pub skip_autogen_comment: bool,
56
57 #[clap(long)]
59 pub skip_package_info: bool,
60
61 #[clap(long)]
63 pub skip_trailing_newline: bool,
64
65 #[clap(long)]
67 pub skip_crate_name: bool,
68
69 #[clap(long)]
71 pub skip_repr_packed: bool,
72
73 #[clap(long)]
75 pub skip_cfg_target_arch: bool,
76
77 #[clap(long)]
79 pub skip_unsafe_code_comment: bool,
80}
81
82impl HouseRules {
83 pub fn all_passes(fix: bool, only_diffed: bool) -> HouseRules {
85 HouseRules {
86 fix,
87 only_diffed,
88 files: Vec::new(),
89 skip_copyright: false,
90 skip_autogen_comment: false,
91 skip_package_info: false,
92 skip_trailing_newline: false,
93 skip_crate_name: false,
94 skip_repr_packed: false,
95 skip_cfg_target_arch: false,
96 skip_unsafe_code_comment: false,
97 }
98 }
99}
100
101#[derive(Debug)]
102enum Files {
103 All,
104 OnlyDiffed,
105 Specific(Vec<PathBuf>),
106}
107
108impl Xtask for HouseRules {
109 fn run(self, ctx: crate::XtaskCtx) -> anyhow::Result<()> {
110 let files = if self.only_diffed {
111 Files::OnlyDiffed
112 } else if self.files.is_empty() {
113 Files::All
114 } else {
115 Files::Specific(self.files)
116 };
117
118 log::trace!("running house-rules on {:?}", files);
119
120 let files = match files {
121 Files::All => git_ls_files()?,
122 Files::OnlyDiffed => git_diffed(ctx.in_git_hook)?,
123 Files::Specific(files) => files,
124 };
125
126 let mut errors = Vec::new();
127 for path in files {
128 if !self.skip_copyright {
129 if let Err(e) = copyright::check_copyright(&path, self.fix) {
130 errors.push(e)
131 }
132 }
133
134 if !self.skip_autogen_comment {
135 if let Err(e) = autogen_comment::check_autogen_comment(&path, self.fix) {
136 errors.push(e)
137 }
138 }
139
140 if !self.skip_package_info {
141 if let Err(e) = package_info::check_package_info(&path, self.fix) {
142 errors.push(e)
143 }
144 }
145
146 if !self.skip_trailing_newline {
147 if let Err(e) = trailing_newline::check_trailing_newline(&path, self.fix) {
148 errors.push(e)
149 }
150 }
151
152 if !self.skip_crate_name {
153 if let Err(e) = crate_name_nodash::check_crate_name_nodash(&path) {
154 errors.push(e)
155 }
156 }
157
158 if !self.skip_repr_packed {
159 if let Err(e) = repr_packed::check_repr_packed(&path, self.fix) {
160 errors.push(e)
161 }
162 }
163
164 if !self.skip_cfg_target_arch {
165 if let Err(e) = cfg_target_arch::check_cfg_target_arch(&path, self.fix) {
166 errors.push(e)
167 }
168 }
169
170 if !self.skip_unsafe_code_comment {
171 if let Err(e) = unsafe_code_comment::check_unsafe_code_comment(&path, self.fix) {
172 errors.push(e)
173 }
174 }
175 }
176
177 for e in &errors {
178 log::error!("{:#}", e);
179 }
180
181 if !errors.is_empty() && !self.fix {
182 Err(anyhow::anyhow!("`house-rules` found formatting errors"))
183 } else {
184 Ok(())
185 }
186 }
187}